home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / unifs.c < prev    next >
C/C++ Source or Header  |  1994-02-11  |  19KB  |  808 lines

  1. /*
  2. Copyright 1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5.  */
  6.  
  7. /* a simple unified file system */
  8.  
  9. #include "mint.h"
  10.  
  11.  
  12. extern FILESYS bios_filesys, proc_filesys, pipe_filesys, shm_filesys;
  13.  
  14. static long    ARGS_ON_STACK uni_root    P_((int drv, fcookie *fc));
  15. static long    ARGS_ON_STACK uni_lookup    P_((fcookie *dir, const char *name, fcookie *fc));
  16. static long    ARGS_ON_STACK uni_getxattr    P_((fcookie *fc, XATTR *xattr));
  17. static long    ARGS_ON_STACK uni_chattr    P_((fcookie *fc, int attrib));
  18. static long    ARGS_ON_STACK uni_chown    P_((fcookie *fc, int uid, int gid));
  19. static long    ARGS_ON_STACK uni_chmode    P_((fcookie *fc, unsigned mode));
  20. static long    ARGS_ON_STACK uni_rmdir    P_((fcookie *dir, const char *name));
  21. static long    ARGS_ON_STACK uni_remove    P_((fcookie *dir, const char *name));
  22. static long    ARGS_ON_STACK uni_getname    P_((fcookie *root, fcookie *dir,
  23.                             char *pathname, int size));
  24. static long    ARGS_ON_STACK uni_rename    P_((fcookie *olddir, char *oldname,
  25.                     fcookie *newdir, const char *newname));
  26. static long    ARGS_ON_STACK uni_opendir    P_((DIR *dirh, int flags));
  27. static long    ARGS_ON_STACK uni_readdir    P_((DIR *dirh, char *nm, int nmlen, fcookie *));
  28. static long    ARGS_ON_STACK uni_rewinddir    P_((DIR *dirh));
  29. static long    ARGS_ON_STACK uni_closedir    P_((DIR *dirh));
  30. static long    ARGS_ON_STACK uni_pathconf    P_((fcookie *dir, int which));
  31. static long    ARGS_ON_STACK uni_dfree    P_((fcookie *dir, long *buf));
  32. static DEVDRV *    ARGS_ON_STACK uni_getdev    P_((fcookie *fc, long *devsp));
  33. static long    ARGS_ON_STACK uni_symlink    P_((fcookie *dir, const char *name, const char *to));
  34. static long    ARGS_ON_STACK uni_readlink    P_((fcookie *fc, char *buf, int buflen));
  35. static long    ARGS_ON_STACK uni_fscntl    P_((fcookie *dir, const char *name, int cmd, long arg));
  36.  
  37. FILESYS uni_filesys = {
  38.     (FILESYS *)0,
  39.     FS_LONGPATH,
  40.     uni_root,
  41.     uni_lookup, nocreat, uni_getdev, uni_getxattr,
  42.     uni_chattr, uni_chown, uni_chmode,
  43.     nomkdir, uni_rmdir, uni_remove, uni_getname, uni_rename,
  44.     uni_opendir, uni_readdir, uni_rewinddir, uni_closedir,
  45.     uni_pathconf, uni_dfree, nowritelabel, noreadlabel,
  46.     uni_symlink, uni_readlink, nohardlink, uni_fscntl, nodskchng
  47. };
  48.  
  49. /*
  50.  * structure that holds files
  51.  * if (mode & S_IFMT == S_IFDIR), then this is an alias for a drive:
  52.  *    "dev" holds the appropriate BIOS device number, and
  53.  *    "data" is meaningless
  54.  * if (mode & S_IFMT == S_IFLNK), then this is a symbolic link:
  55.  *    "dev" holds the user id of the owner, and
  56.  *    "data" points to the actual link data
  57.  */
  58.  
  59. typedef struct unifile {
  60.     char name[NAME_MAX+1];
  61.     ushort mode;
  62.     ushort dev;
  63.     FILESYS *fs;
  64.     void *data;
  65.     struct unifile *next;
  66. } UNIFILE;
  67.  
  68. static UNIFILE u_drvs[UNI_NUM_DRVS];
  69. static UNIFILE *u_root = 0;
  70.  
  71. static long    do_ulookup    P_((fcookie *, const char *, fcookie *, UNIFILE **));
  72.  
  73. FILESYS *
  74. get_filesys (dev)
  75.      int dev;
  76. {
  77.   UNIFILE *u;
  78.  
  79.   for (u = u_root; u; u = u->next)
  80.     if (u->dev == dev)
  81.       return u->fs;
  82.   return (FILESYS *) 0L;
  83. }
  84.  
  85. void
  86. unifs_init()
  87. {
  88.     UNIFILE *u = u_drvs;
  89.     int i;
  90.  
  91.     u_root = u;
  92.     for (i = 0; i < UNI_NUM_DRVS; i++,u++) {
  93.         u->next = u+1;
  94.         u->mode = S_IFDIR|DEFAULT_DIRMODE;
  95.         u->dev = i;
  96.         if (i == PROCDRV) {
  97.             strcpy(u->name, "proc");
  98.             u->fs = &proc_filesys;
  99.         } else if (i == PIPEDRV) {
  100.             strcpy(u->name, "pipe");
  101.             u->fs = &pipe_filesys;
  102.         } else if (i == BIOSDRV) {
  103.             strcpy(u->name, "dev");
  104.             u->fs = &bios_filesys;
  105.         } else if (i == UNIDRV) {
  106.             (u-1)->next = u->next;    /* skip this drive */
  107.         } else if (i == SHMDRV) {
  108.             strcpy(u->name, "shm");
  109.             u->fs = &shm_filesys;
  110.         } else {
  111.             u->name[0] = i + 'a';
  112.             u->name[1] = 0;
  113.             u->fs = 0;
  114.         }
  115.     }
  116.     --u;    /* oops, we went too far */
  117.     u->next = 0;
  118. }
  119.  
  120. static long ARGS_ON_STACK 
  121. uni_root(drv, fc)
  122.     int drv;
  123.     fcookie *fc;
  124. {
  125.     if (drv == UNIDRV) {
  126.         fc->fs = &uni_filesys;
  127.         fc->dev = drv;
  128.         fc->index = 0L;
  129.         return 0;
  130.     }
  131.     fc->fs = 0;
  132.     return EINTRN;
  133. }
  134.  
  135. static long ARGS_ON_STACK 
  136. uni_lookup(dir, name, fc)
  137.     fcookie *dir;
  138.     const char *name;
  139.     fcookie *fc;
  140. {
  141.     return do_ulookup(dir, name, fc, (UNIFILE **)0);
  142. }
  143.  
  144. /* worker function for uni_lookup; can also return the UNIFILE
  145.  * pointer for the root directory
  146.  */
  147. static long
  148. do_ulookup(dir, name, fc, up)
  149.     fcookie *dir;
  150.     const char *name;
  151.     fcookie *fc;
  152.     UNIFILE **up;
  153. {
  154.     UNIFILE *u;
  155.     long drvs;
  156.     FILESYS *fs;
  157.     fcookie *tmp;
  158.     extern long dosdrvs;
  159.  
  160.     TRACE(("uni_lookup(%s)", name));
  161.  
  162.     if (dir->index != 0) {
  163.         DEBUG(("uni_lookup: bad directory"));
  164.         return EPTHNF;
  165.     }
  166. /* special case: an empty name in a directory means that directory */
  167. /* so do "." and ".." */
  168.  
  169.     if (!*name || !strcmp(name, ".") || !strcmp(name, "..")) {
  170.         dup_cookie(fc, dir);
  171.         return 0;
  172.     }
  173.     drvs = drvmap() | dosdrvs | PSEUDODRVS;
  174. /*
  175.  * OK, check the list of aliases and special directories
  176.  */
  177.     for (u = u_root; u; u = u->next) {
  178.         if (!stricmp(name, u->name)) {
  179.             if ( (u->mode & S_IFMT) == S_IFDIR ) {
  180.                 if (u->dev >= NUM_DRIVES) {
  181.                     fs = u->fs;
  182.                     if (up) *up = u;
  183.                     return (*fs->root)(u->dev,fc);
  184.                 }
  185.                 if ((drvs & (1L << u->dev)) == 0)
  186.                     return EPTHNF;
  187.                 tmp = &curproc->root[u->dev];
  188.                 if (!tmp->fs) {        /* drive changed? */
  189.                     changedrv(tmp->dev);
  190.                     tmp = &curproc->root[u->dev];
  191.                     if (!tmp->fs)
  192.                         return EPTHNF;
  193.                 }
  194.                 dup_cookie(fc, tmp);
  195.             } else {        /* a symbolic link */
  196.                 fc->fs = &uni_filesys;
  197.                 fc->dev = UNIDRV;
  198.                 fc->index = (long)u;
  199.             }
  200.             if (up) *up = u;
  201.             return 0;
  202.         }
  203.     }
  204.     DEBUG(("uni_lookup: name (%s) not found", name));
  205.     return EFILNF;
  206. }
  207.  
  208. static long ARGS_ON_STACK 
  209. uni_getxattr(fc, xattr)
  210.     fcookie *fc;
  211.     XATTR *xattr;
  212. {
  213.     UNIFILE *u = (UNIFILE *)fc->index;
  214.  
  215.     if (fc->fs != &uni_filesys) {
  216.         ALERT("ERROR: wrong file system getxattr called");
  217.         return EINTRN;
  218.     }
  219.  
  220.     xattr->index = fc->index;
  221.     xattr->dev = fc->dev;
  222.     xattr->nlink = 1;
  223.     xattr->blksize = 1;
  224.  
  225. /* If "u" is null, then we have the root directory, otherwise
  226.  * we use the UNIFILE structure to get the info about it
  227.  */
  228.     if (!u || ( (u->mode & S_IFMT) == S_IFDIR )) {
  229.         xattr->uid = xattr->gid = 0;
  230.         xattr->size = xattr->nblocks = 0;
  231.         xattr->mode = S_IFDIR | DEFAULT_DIRMODE;
  232.         xattr->attr = FA_DIR;
  233.     } else {
  234.         xattr->uid = u->dev;
  235.         xattr->gid = 0;
  236.         xattr->size = xattr->nblocks = strlen(u->data) + 1;
  237.         xattr->mode = u->mode;
  238.         xattr->attr = 0;
  239.     }
  240.     xattr->mtime = xattr->atime = xattr->ctime = 0;
  241.     xattr->mdate = xattr->adate = xattr->cdate = 0;
  242.     return 0;
  243. }
  244.  
  245. static long ARGS_ON_STACK 
  246. uni_chattr(dir, attrib)
  247.     fcookie *dir;
  248.     int attrib;
  249. {
  250.     UNUSED(dir); UNUSED(attrib);
  251.     return EACCDN;
  252. }
  253.  
  254. static long ARGS_ON_STACK 
  255. uni_chown(dir, uid, gid)
  256.     fcookie *dir;
  257.     int uid, gid;
  258. {
  259.     UNUSED(dir); UNUSED(uid);
  260.     UNUSED(gid);
  261.     return EINVFN;
  262. }
  263.  
  264. static long ARGS_ON_STACK 
  265. uni_chmode(dir, mode)
  266.     fcookie *dir;
  267.     unsigned mode;
  268. {
  269.     UNUSED(dir);
  270.     UNUSED(mode);
  271.     return EINVFN;
  272. }
  273.  
  274. static long ARGS_ON_STACK 
  275. uni_rmdir(dir, name)
  276.     fcookie *dir;
  277.     const char *name;
  278. {
  279.     long r;
  280.  
  281.     r = uni_remove(dir, name);
  282.     if (r == EFILNF) r = EPTHNF;
  283.     return r;
  284. }
  285.  
  286. static long ARGS_ON_STACK 
  287. uni_remove(dir, name)
  288.     fcookie *dir;
  289.     const char *name;
  290. {
  291.     UNIFILE *u, *lastu;
  292.  
  293.     UNUSED(dir);
  294.  
  295.     lastu = 0;
  296.     u = u_root;
  297.     while (u) {
  298.         if (!strncmp(u->name, name, NAME_MAX)) {
  299.             if ( (u->mode & S_IFMT) != S_IFLNK ) return EFILNF;
  300.             kfree(u->data);
  301.             if (lastu)
  302.                 lastu->next = u->next;
  303.             else
  304.                 u_root = u->next;
  305.             kfree(u);
  306.             return 0;
  307.         }
  308.         lastu = u;
  309.         u = u->next;
  310.     }
  311.     return EFILNF;
  312. }
  313.  
  314. static long ARGS_ON_STACK 
  315. uni_getname(root, dir, pathname, size)
  316.     fcookie *root, *dir; char *pathname;
  317.     int size;
  318. {
  319.     FILESYS *fs;
  320.     UNIFILE *u;
  321.     char *n;
  322.     fcookie relto;
  323.     char tmppath[PATH_MAX];
  324.     long r;
  325.  
  326.     UNUSED(root);
  327.  
  328.     if (size <= 0) return ERANGE;
  329.  
  330.     fs = dir->fs;
  331.     if (dir->dev == UNIDRV) {
  332.         *pathname = 0;
  333.         return 0;
  334.     }
  335.  
  336.     for (u = u_root; u; u = u->next) {
  337.         if (dir->dev == u->dev && (u->mode & S_IFMT) == S_IFDIR) {
  338.             *pathname++ = '\\';
  339.             if (--size <= 0) return ERANGE;
  340.             for (n = u->name; *n; ) {
  341.                 *pathname++ = *n++;
  342.                 if (--size <= 0) return ERANGE;
  343.             }
  344.             break;
  345.         }
  346.     }
  347.  
  348.     if (!u) {
  349.         ALERT("unifs: couldn't match a drive with a directory");
  350.         return EPTHNF;
  351.     }
  352.  
  353.     if (dir->dev >= NUM_DRIVES) {
  354.         if ((*fs->root)(dir->dev, &relto) == 0) {
  355.             if (!(fs->fsflags & FS_LONGPATH)) {
  356.                 r = (*fs->getname)(&relto, dir, tmppath, PATH_MAX);
  357.                 release_cookie(&relto);
  358.                 if (r) {
  359.                     return r;
  360.                 }
  361.                 if (strlen(tmppath) < size) {
  362.                     strcpy(pathname, tmppath);
  363.                     return 0;
  364.                 } else {
  365.                     return ERANGE;
  366.                 }
  367.             }
  368.             r = (*fs->getname)(&relto, dir, pathname, size);
  369.             release_cookie(&relto);
  370.             return r;
  371.         } else {
  372.             *pathname = 0;
  373.             return EINTRN;
  374.         }
  375.     }
  376.  
  377.     if (curproc->root[dir->dev].fs != fs) {
  378.         ALERT("unifs: drive's file system doesn't match directory's");
  379.         return EINTRN;
  380.     }
  381.  
  382.     if (!(fs->fsflags & FS_LONGPATH)) {
  383.         r = (*fs->getname)(&curproc->root[dir->dev], dir, tmppath, PATH_MAX);
  384.         if (r) return r;
  385.         if (strlen(tmppath) < size) {
  386.             strcpy(pathname, tmppath);
  387.             return 0;
  388.         } else {
  389.             return ERANGE;
  390.         }
  391.     }
  392.     return (*fs->getname)(&curproc->root[dir->dev], dir, pathname, size);
  393. }
  394.  
  395. static long ARGS_ON_STACK 
  396. uni_rename(olddir, oldname, newdir, newname)
  397.     fcookie *olddir;
  398.     char *oldname;
  399.     fcookie *newdir;
  400.     const char *newname;
  401. {
  402.     UNIFILE *u;
  403.     fcookie fc;
  404.     long r;
  405.  
  406.     UNUSED(olddir);
  407.  
  408.     for (u = u_root; u; u = u->next) {
  409.         if (!stricmp(u->name, oldname))
  410.             break;
  411.     }
  412.  
  413.     if (!u) {
  414.         DEBUG(("uni_rename: old file not found"));
  415.         return EFILNF;
  416.     }
  417.  
  418. /* the new name is not allowed to exist! */
  419.     r = uni_lookup(newdir, newname, &fc);
  420.     if (r == 0)
  421.         release_cookie(&fc);
  422.  
  423.     if (r != EFILNF) {
  424.         DEBUG(("uni_rename: error %ld", r));
  425.         return (r == 0) ? EACCDN : r;
  426.     }
  427.  
  428.     (void)strncpy(u->name, newname, NAME_MAX);
  429.     return 0;
  430. }
  431.  
  432. static long ARGS_ON_STACK 
  433. uni_opendir(dirh, flags)
  434.     DIR *dirh;
  435.     int flags;
  436. {
  437.     UNUSED(flags);
  438.  
  439.     if (dirh->fc.index != 0) {
  440.         DEBUG(("uni_opendir: bad directory"));
  441.         return EPTHNF;
  442.     }
  443.     dirh->index = 0;
  444.     return 0;
  445. }
  446.  
  447.  
  448. static long ARGS_ON_STACK 
  449. uni_readdir(dirh, name, namelen, fc)
  450.     DIR *dirh;
  451.     char *name;
  452.     int namelen;
  453.     fcookie *fc;
  454. {
  455.     long map;
  456.     char *dirname;
  457.     int i;
  458.     int giveindex = (dirh->flags == 0);
  459.     UNIFILE *u;
  460.     long index;
  461.     extern long dosdrvs;
  462.     long r;
  463.  
  464.     map = dosdrvs | drvmap() | PSEUDODRVS;
  465.     i = dirh->index++;
  466.     u = u_root;
  467.     while (i > 0) {
  468.         --i;
  469.         u = u->next;
  470.         if (!u)
  471.             break;
  472.     }
  473. tryagain:
  474.     if (!u) return ENMFIL;
  475.  
  476.     dirname = u->name;
  477.     index = (long)u;
  478.     if ( (u->mode & S_IFMT) == S_IFDIR ) {
  479. /* make sure the drive really exists */
  480.         if ( u->dev >= NUM_DRIVES) {
  481.             r = (*u->fs->root)(u->dev,fc);
  482.             if (r) {
  483.             fc->fs = &uni_filesys;
  484.             fc->index = 0;
  485.             fc->dev = u->dev;
  486.             }
  487.         } else {
  488.             if ((map & (1L << u->dev)) == 0 ) {
  489.             dirh->index++;
  490.             u = u->next;
  491.             goto tryagain;
  492.             }
  493.             dup_cookie(fc, &curproc->root[u->dev]);
  494.             if (!fc->fs) {    /* drive not yet initialized */
  495.         /* use default attributes */
  496.             fc->fs = &uni_filesys;
  497.             fc->index = 0;
  498.             fc->dev = u->dev;
  499.             }
  500.         }
  501.     } else {        /* a symbolic link */
  502.         fc->fs = &uni_filesys;
  503.         fc->dev = UNIDRV;
  504.         fc->index = (long)u;
  505.     }
  506.  
  507.     if (giveindex) {
  508.         namelen -= (int)sizeof(long);
  509.         if (namelen <= 0) {
  510.             release_cookie(fc);
  511.             return ERANGE;
  512.         }
  513.         *((long *)name) = index;
  514.         name += sizeof(long);
  515.     }
  516.     strncpy(name, dirname, namelen-1);
  517.     if (strlen(name) < strlen(dirname)) {
  518.         release_cookie(fc);
  519.         return ENAMETOOLONG;
  520.     }
  521.     return 0;
  522. }
  523.  
  524. static long ARGS_ON_STACK 
  525. uni_rewinddir(dirh)
  526.     DIR *dirh;
  527. {
  528.     dirh->index = 0;
  529.     return 0;
  530. }
  531.  
  532. static long ARGS_ON_STACK 
  533. uni_closedir(dirh)
  534.     DIR *dirh;
  535. {
  536.     UNUSED(dirh);
  537.     return 0;
  538. }
  539.  
  540. static long ARGS_ON_STACK 
  541. uni_pathconf(dir, which)
  542.     fcookie *dir;
  543.     int which;
  544. {
  545.     UNUSED(dir);
  546.  
  547.     switch(which) {
  548.     case -1:
  549.         return DP_MAXREQ;
  550.     case DP_IOPEN:
  551.         return 0;        /* no files to open */
  552.     case DP_MAXLINKS:
  553.         return 1;        /* no hard links available */
  554.     case DP_PATHMAX:
  555.         return PATH_MAX;
  556.     case DP_NAMEMAX:
  557.         return NAME_MAX;
  558.     case DP_ATOMIC:
  559.         return 1;        /* no atomic writes */
  560.     case DP_TRUNC:
  561.         return DP_AUTOTRUNC;
  562.     case DP_CASE:
  563.         return DP_CASEINSENS;
  564.     default:
  565.         return EINVFN;
  566.     }
  567. }
  568.  
  569. static long ARGS_ON_STACK 
  570. uni_dfree(dir, buf)
  571.     fcookie *dir;
  572.     long *buf;
  573. {
  574.     UNUSED(dir);
  575.  
  576.     buf[0] = 0;    /* number of free clusters */
  577.     buf[1] = 0;    /* total number of clusters */
  578.     buf[2] = 1;    /* sector size (bytes) */
  579.     buf[3] = 1;    /* cluster size (sectors) */
  580.     return 0;
  581. }
  582.  
  583. static DEVDRV * ARGS_ON_STACK 
  584. uni_getdev(fc, devsp)
  585.     fcookie *fc;
  586.     long *devsp;
  587. {
  588.     UNUSED(fc);
  589.  
  590.     *devsp = EACCDN;
  591.     return 0;
  592. }
  593.  
  594. static long ARGS_ON_STACK 
  595. uni_symlink(dir, name, to)
  596.     fcookie *dir;
  597.     const char *name;
  598.     const char *to;
  599. {
  600.     UNIFILE *u;
  601.     fcookie fc;
  602.     long r;
  603.  
  604.     r = uni_lookup(dir, name, &fc);
  605.     if (r == 0) {
  606.         release_cookie(&fc);
  607.         return EACCDN;    /* file already exists */
  608.     }
  609.     if (r != EFILNF) return r;    /* some other error */
  610.  
  611.     u = kmalloc(SIZEOF(UNIFILE));
  612.     if (!u) return EACCDN;
  613.  
  614.     strncpy(u->name, name, NAME_MAX);
  615.     u->name[NAME_MAX] = 0;
  616.  
  617.     u->data = kmalloc((long)strlen(to)+1);
  618.     if (!u->data) {
  619.         kfree(u);
  620.         return EACCDN;
  621.     }
  622.     strcpy(u->data, to);
  623.     u->mode = S_IFLNK | DEFAULT_DIRMODE;
  624.     u->dev = curproc->ruid;
  625.     u->next = u_root;
  626.     u->fs = &uni_filesys;
  627.     u_root = u;
  628.     return 0;
  629. }
  630.  
  631. static long ARGS_ON_STACK 
  632. uni_readlink(fc, buf, buflen)
  633.     fcookie *fc;
  634.     char *buf;
  635.     int buflen;
  636. {
  637.     UNIFILE *u;
  638.  
  639.     u = (UNIFILE *)fc->index;
  640.     assert(u);
  641.     assert((u->mode & S_IFMT) == S_IFLNK);
  642.     assert(u->data);
  643.     strncpy(buf, u->data, buflen);
  644.     if (strlen(u->data) >= buflen)
  645.         return ENAMETOOLONG;
  646.     return 0;
  647. }
  648.  
  649.  
  650.  
  651.  
  652. /* uk: use these Dcntl's to install a new filesystem which is only visible
  653.  *     on drive u:
  654.  *
  655.  *     FS_INSTALL:   let the kernel know about the file system; it does NOT
  656.  *                   get a device number.
  657.  *     FS_MOUNT:     use Dcntl(FS_MOUNT, "u:\\foo", &descr) to make a directory
  658.  *                   foo where the filesytem resides in; the file system now
  659.  *                   gets its device number which is also written into the
  660.  *                   dev_no field of the fs_descr structure.
  661.  *     FS_UNMOUNT:   remove a file system's directory; this call closes all
  662.  *                   open files, directory searches and directories on this
  663.  *                   device. Make sure that the FS will not recognise any
  664.  *                   accesses to this device, as fs->root will be called
  665.  *                   during the reinitalisation!
  666.  *     FS_UNINSTALL: remove a file system completely from the kernel list,
  667.  *                   but that will only be possible if there is no directory
  668.  *                   associated with this file system.
  669.  *                   This function allows it to write file systems as demons
  670.  *                   which stay in memory only as long as needed.
  671.  *
  672.  * BUG: it is not possible yet to lock such a filesystem.
  673.  */
  674.  
  675. /* here we start with gemdos only file system device numbers */
  676. static curr_dev_no = 0x100;
  677.  
  678.  
  679.  
  680. static long ARGS_ON_STACK
  681. uni_fscntl(dir, name, cmd, arg)
  682.     fcookie *dir;
  683.     const char *name;
  684.     int cmd;
  685.     long arg;
  686. {
  687.     fcookie fc;
  688.     long r;
  689.  
  690.     extern struct kerinfo kernelinfo;
  691.     extern FILESYS *active_fs;
  692.  
  693.     if (cmd == FS_INSTALL) { /* install a new filesystem */
  694.         struct fs_descr *d = (struct fs_descr*)arg;
  695.         FILESYS *fs;
  696.  
  697.     /* check if FS is installed already */
  698.         for (fs = active_fs;  fs;  fs = fs->next)
  699.             if (d->file_system == fs)  return 0L;
  700.     /* include new file system into chain of file systems */
  701.         d->file_system->next = active_fs;
  702.         active_fs = d->file_system;
  703.         return (long)&kernelinfo;  /* return pointer to kernel info as OK */
  704.     } else if (cmd == FS_MOUNT) {  /* install a new gemdos-only device for this FS */
  705.         struct fs_descr *d = (struct fs_descr*)arg;
  706.         FILESYS *fs;
  707.         UNIFILE *u;
  708.  
  709.     /* first check for existing names */
  710.         r = uni_lookup(dir, name, &fc);
  711.         if (r == 0) {
  712.             release_cookie(&fc);
  713.             return EACCDN;   /* name exists already */
  714.         }
  715.         if (r != EFILNF) return r; /* some other error */
  716.         if (!d) return EACCDN;
  717.         if (!d->file_system) return EACCDN;
  718.     /* check if FS is installed */
  719.         for (fs = active_fs;  fs;  fs = fs->next)
  720.             if (d->file_system == fs)  break;
  721.         if (!fs) return EACCDN;  /* not installed, so return an error */
  722.         u = kmalloc(SIZEOF(UNIFILE));
  723.         if (!u) return EACCDN;
  724.         strncpy(u->name, name, NAME_MAX);
  725.         u->name[NAME_MAX] = 0;
  726.         u->mode = S_IFDIR|DEFAULT_DIRMODE;
  727.         u->data = 0;
  728.         u->fs = d->file_system;
  729.     /* now get the file system its own device number */
  730.         u->dev = d->dev_no = curr_dev_no++;
  731.     /* chain new entry into unifile list */
  732.         u->next = u_root;
  733.         u_root = u;
  734.         return (long)u->dev;
  735.     } else if (cmd == FS_UNMOUNT) {  /* remove a file system's directory */
  736.         struct fs_descr *d = (struct fs_descr*)arg;
  737.         FILESYS *fs;
  738.         UNIFILE *u;
  739.  
  740.     /* first check that directory exists */
  741.     /* use special uni_lookup mode to get the unifile entry */
  742.         r = do_ulookup(dir, name, &fc, &u);
  743.         if (r != 0)  return EFILNF;   /* name does not exist */
  744.         if (!d) return EFILNF;
  745.         if (!d->file_system) return EFILNF;
  746.         if (d->file_system != fc.fs)
  747.             return EFILNF;  /* not the right name! */
  748.         release_cookie(&fc);
  749.  
  750.         if (!u || (u->fs != d->file_system))
  751.             return EFILNF;
  752.     /* check if FS is installed */
  753.         for (fs = active_fs;  fs;  fs = fs->next)
  754.             if (d->file_system == fs)  break;
  755.         if (!fs) return EACCDN;  /* not installed, so return an error */
  756.  
  757.     /* here comes the difficult part: we have to close all files on that
  758.      * device, so we have to call changedrv(). The file system driver
  759.      * has to make sure that further calls to fs.root() with this device
  760.      * number will fail!
  761.      *
  762.      * Kludge: mark the directory as a link, so uni_remove will remove it.
  763.      */
  764.         changedrv(u->dev);
  765.         u->mode &= ~S_IFMT;
  766.         u->mode |= S_IFLNK;
  767.         return uni_remove(dir, name);
  768.     } else if (cmd == FS_UNINSTALL) {    /* remove file system from kernel list */
  769.         struct fs_descr *d = (struct fs_descr*)arg;
  770.         FILESYS *fs, *last_fs;
  771.         UNIFILE *u;
  772.  
  773.     /* first check if there are any files or directories associated with
  774.      * this file system
  775.      */
  776.         for (u = u_root;  u;  u = u->next)
  777.             if (u->fs == d->file_system)
  778.                 return EACCDN;   /* we cannot remove it before unmount */
  779.         last_fs = 0;
  780.         fs = active_fs;
  781.         while (fs)  {   /* go through the list and remove the file system */
  782.             if (fs == d->file_system)  {
  783.                 if (last_fs)
  784.                     last_fs->next = fs->next;
  785.                 else
  786.                     active_fs = fs->next;
  787.                 d->file_system->next = 0;
  788.                 return 0;
  789.             }
  790.             last_fs = fs;
  791.             fs = fs->next;
  792.         }
  793.         return EFILNF;
  794.     } else {
  795.     /* see if we should just pass this along to another file system */
  796.         r = uni_lookup(dir, name, &fc);
  797.         if (r == 0) {
  798.             if (fc.fs != &uni_filesys) {
  799.                 r = (*fc.fs->fscntl)(&fc, ".", cmd, arg);
  800.                 release_cookie(&fc);
  801.                 return r;
  802.             }
  803.             release_cookie(&fc);
  804.         }
  805.     }
  806.     return EINVFN;
  807. }
  808.